/*
 * @lc app=leetcode.cn id=51 lang=java
 *
 * [51] N 皇后
 *
 * https://leetcode.cn/problems/n-queens/description/
 *
 * algorithms
 * Hard (74.01%)
 * Likes:    1370
 * Dislikes: 0
 * Total Accepted:    221.4K
 * Total Submissions: 299.1K
 * Testcase Example:  '4'
 *
 * 按照国际象棋的规则，皇后可以攻击与之处在同一行或同一列或同一斜线上的棋子。
 * 
 * n 皇后问题 研究的是如何将 n 个皇后放置在 n×n 的棋盘上，并且使皇后彼此之间不能相互攻击。
 * 
 * 给你一个整数 n ，返回所有不同的 n 皇后问题 的解决方案。
 * 
 * 
 * 
 * 每一种解法包含一个不同的 n 皇后问题 的棋子放置方案，该方案中 'Q' 和 '.' 分别代表了皇后和空位。
 * 
 * 
 * 
 * 示例 1：
 * 
 * 
 * 输入：n = 4
 * 输出：[[".Q..","...Q","Q...","..Q."],["..Q.","Q...","...Q",".Q.."]]
 * 解释：如上图所示，4 皇后问题存在两个不同的解法。
 * 
 * 
 * 示例 2：
 * 
 * 
 * 输入：n = 1
 * 输出：[["Q"]]
 * 
 * 
 * 
 * 
 * 提示：
 * 
 * 
 * 1 <= n <= 9
 * 
 * 
 * 
 * 
 */

// @lc code=start
class Solution {
    List<List<String>> res = new ArrayList<>();

    public List<List<String>> solveNQueens(int n) {
        char[][] board = new char[n][n];
        backTrack(board, 0);
        return res;
    }

    // 每行
    void backTrack(char[][] board, int row) {
        if (row == board.length) {
            res.add(char2String(board));
            return;
        }
        // 行确定，遍历列
        for (int i = 0; i < board.length; i++) {
            // 会被攻击的情况，检查左上、右上、上
            if (isInvalid(board, row, i))
                continue;
            // 不会被攻击的情况，做选择
            board[row][i] = 'Q';
            backTrack(board, row + 1);
            board[row][i] = '.';
        }
    }

    List<String> char2String(char[][] board) {
        List<String> result = new ArrayList<>();
        for (int i = 0; i < board.length; i++) {
            for (int j = 0; j < board[i].length; j++) {
                if (board[i][j] == '\u0000') {
                    board[i][j] = '.';
                }
            }
            result.add(new String(board[i]));
        }
        return result;
    }

    boolean isInvalid(char[][] board, int row, int col) {
        // 检查列
        for (int i = 0; i <= row; i++) {
            if (board[i][col] == 'Q')
                return true;
        }
        // 左上
        for (int i = row - 1, j = col - 1; i >= 0 && j >= 0; i--, j--) {
            if (board[i][j] == 'Q')
                return true;
        }
        // 右上
        for (int i = row - 1, j = col + 1; i >= 0 && j < board.length; i--, j++) {
            if (board[i][j] == 'Q')
                return true;
        }
        return false;
    }
}
// @lc code=end
